package cn.pku.edu.cs.ldn.thread;

import java.util.HashMap;
import java.util.Map;

import cn.pku.edu.cs.ldn.util.FileUtil;

import android.util.Log;

/**
 * @author ldn
 * 
 */
public class FileDownloadManager {
	private static final String TAG = "FileDownloadManager";
	private static final boolean DEBUG = true;

	private Map<String, ObservableThread> downloadingThreads = null;

	private static FileDownloadManager instance = null;

	public static FileDownloadManager getInstance() {
		synchronized (FileDownloadManager.class) {
			if (instance == null) {
				instance = new FileDownloadManager();
			}
			return instance;
		}
	}

	/**
	 * initialization
	 */
	private FileDownloadManager() {
	}

	public void requestDownloadFile(final String remotePath, String localPath,
			ThreadObserverHandler handler) {
		synchronized (FileDownloadManager.this) {
			if (FileUtil.isRemoteFileCached(remotePath)) {
				if (DEBUG)
					Log.v(TAG,
							"requestDownloadFile: file requested has already been downloaded");
				if (handler != null) {
					handler.postRun(null);
				}
				return;
			}
			if (isDownloading(remotePath)) {
				if (DEBUG)
					Log.v(TAG,
							"requestDownloadFile: file requested is already downloading");
				if (handler != null) {
					ObservableThread thread = downloadingThreads
							.get(remotePath);
					if (thread == null) {
						if (DEBUG)
							Log.e(TAG, "requestDownloadFile: error, return");
						return;
					}
					thread.addObserver(handler);
				}
				return;
			}
			HttpDownloadThread thread = getDownloadThread(remotePath,
					localPath, handler);
			if (downloadingThreads == null) {
				downloadingThreads = new HashMap<String, ObservableThread>(5);
			}
			downloadingThreads.put(remotePath, thread);
			ThreadObserverHandler threadObserverHandler = new ThreadObserverHandler() {

				@Override
				public void preRun() {

				}

				@Override
				public void postRun(Object object) {
					if (DEBUG)
						Log.v(TAG, "postRun");
					if (downloadingThreads != null) {
						downloadingThreads.remove(remotePath);
					} else {
						if (DEBUG)
							Log.e(TAG,
									"postRun: downloadingThreads is null, but at least one exist");
					}
				}

				@Override
				public void inRun(float processed, float total) {

				}

				@Override
				public void onStop() {
					if (DEBUG)
						Log.v(TAG, "onStop");
					if (downloadingThreads != null) {
						downloadingThreads.remove(remotePath);
					} else {
						if (DEBUG)
							Log.e(TAG,
									"onStop: downloadingThreads is null, but at least one exist");
					}
				}
			};
			thread.addObserver(threadObserverHandler);
			thread.start();
		}
	}

	public void requestCancelDownloadFile(final String remotePath,
			ThreadObserverHandler handler) {
		if (downloadingThreads == null) {
			return;
		}
		ObservableThread thread = downloadingThreads.get(remotePath);
		if (thread == null) {
			return;
		}
		thread.removeObserver(handler);
	}

	/**
	 * Just return a new download thread, will implement a thread pool in the
	 * future
	 * 
	 * @param remotePath
	 * @param localPath
	 * @param handler
	 * @return
	 */
	public HttpDownloadThread getDownloadThread(String remotePath,
			String localPath, ThreadObserverHandler handler) {
		// TODO
		HttpDownloadThread thread = new HttpDownloadThread(remotePath,
				localPath, handler);
		return thread;
	}

	public ImageDownloadThread getImageDownloadThread(String remotePath,
			String localPath, ThreadObserverHandler handler) {
		ImageDownloadThread thread = new ImageDownloadThread(remotePath,
				localPath, handler);
		return thread;
	}

	/**
	 * check if there is a thread downloading this file
	 * 
	 * @param remotePath
	 * @return
	 */
	private boolean isDownloading(String remotePath) {
		if (downloadingThreads == null) {
			return false;
		}
		if (downloadingThreads.containsKey(remotePath)) {
			return true;
		}
		return false;
	}
}
